/*
 * Region.h
 *
 *  Created on: Jun 2, 2011
 *      Author: hongyang
 */

#ifndef REGION_H_
#define REGION_H_

#include "Block.h"
#include "Board.h"
#include "../smartgame/SgVector.h"
#include "../smartgame/SgPointSet.h"
#include "GoEyeCount.h"
#include "GoEyeUtil.h"

enum RegionFlag {
	REGION_COMPUTED_BLOCKS,
	REGION_SMALL,
	REGION_CORRIDOR,
	REGION_SAFE,
	REGION_FLAG_COUNT
};

typedef std::bitset<REGION_FLAG_COUNT> RegionFlags;

class Region {
public:
	Region(const Board& board, SgBlackWhite color);
	~Region();

	bool operator==(const Region& r) {
		return id = r.id;
	}
	void init();

	bool isInterior(const Block* block) const;
	bool isBoundary(const Block* block) const;

	void addBlock(Block* b);
	void removeBlock(Block* b);

	void addStone(SgPoint p);
	void removeStone(SgPoint p);

	int getId() const;

	bool enoughEyes();

	SgPointSet area() const;
	SgBlackWhite getColor() const;
	SgPointSet boundary(bool pickColor) const;
	void findBlocks();
	const SgVectorOf<Block>& getBlocks() const {
		return blocks;
	}

	void print() const;

	/**
	 * may be analyzed through some simple measurements, e.g. group strength.
	 */
	bool isConnected() const;

    void computeSingleBlockEyeSpace();

    void computeMultipleBlockEyeSpace();

	void computeEyeSpace();

	void computeStrength();

	int getStrength();

	int numPoints() const {
		int num = 0;
		for(SgVectorIteratorOf<Block> sit(blocks); sit; ++sit)
			num += (*sit)->numPoints();
		return num;
	}

	int numBlocks() const {
		return blocks.Length();
	}

	bool isAlive() const {
		return true;
	}

	GoEyeCount getEyeCount(){
		computeEyeSpace();
		return eyeCount;
	}

	void setDelete() {
		deleted = true;
	}

	bool isDeleted() {
		return deleted;
	}

	bool containsBlock(Block* b) const {
		return blocks.Contains(b);
	}

private:
	const Board& board;
	RegionFlags flags;
	//SgPointSet points;
	SgBlackWhite player;
	SgVectorOf<Block> blocks;
	GoEyeCount eyeCount;
	int strength;
	bool deleted;

	int id;

	static int alloc_num;
};

inline void Region::addBlock(Block* b) {
	blocks.Include(b);
}

inline void Region::removeBlock(Block* b) {
	bool f = blocks.Exclude(b);
	SG_ASSERT(f);
}

inline SgPointSet Region::area() const {
	SgPointSet set;
	for(SgVectorIteratorOf<Block> sit(blocks); sit; ++sit) {
		set |= (*sit)->pointSet();
	}
	return set;
}

inline SgBlackWhite Region::getColor() const {
	return player;
}

inline int Region::getId() const {
	return id;
}

inline bool Region::isBoundary(const Block* b) const {
	return !isInterior(b);
}

inline void Region::print() const {
	SgDebug() << "region " << SgBW(player) << " id " << id << "\n";
	for(SgVectorIteratorOf<Block> sit(blocks); sit; ++sit)
		(*sit)->print();
}

#endif /* REGION_H_ */
